<template>
  <div id="sukodu" :style="{ '--cell-number': cellNumber }">
    <!-- 内容 -->
    <div class="container">
      <!-- 选择格子 -->
      <div class="select-box" style="margin-bottom: 10px">
        <el-select v-model="cellNumber" size="small" @change="generateSukodu">
          <el-option
            v-for="cell in cellOptions"
            :key="cell.label"
            :label="cell.label"
            :value="cell.value"
          ></el-option>
        </el-select>
        <el-button type="primary" size="small" @click="generateSukodu">
          生成
        </el-button>
      </div>
      <div class="select-box">
        <el-button
          type="info"
          size="small"
          v-if="tipNumber > 0"
          @click="tipState = !tipState"
        >
          {{ tipState ? "取消" : "提示" }}
        </el-button>
        <el-button
          :type="clickState ? 'primary' : 'danger'"
          size="small"
          @click="clickState = !clickState"
          >{{ clickState ? "标记" : "填充" }}</el-button
        >
      </div>
      <div class="position-box">
        <!-- 行提示 -->
        <div class="row-hints">
          <div
            class="row-hints-box"
            v-for="(rowHint, index) in rowHintsArray"
            :key="'row-hint-' + index + Math.random() * 1000000"
            @click="tipClick('row', index)"
          >
            <p
              v-for="hint in rowHint"
              :key="'row-hint_' + index + Math.random() * 1000000"
            >
              {{ hint }}
            </p>
          </div>
        </div>
        <!-- 数独格子 -->
        <div class="sukodu-box">
          <div
            class="row-box"
            v-for="(row, rowIndex) in cellArray"
            :key="'row-' + rowIndex + Math.random() * 1000000"
          >
            <div
              class="col-box"
              v-for="(col, colIndex) in row"
              :key="'col-' + colIndex + Math.random() * 1000000"
              :class="{ 'col-stuff': col == 1, 'col-mark': col == 2 }"
              @click="cellClick(rowIndex, colIndex)"
            ></div>
          </div>
        </div>
        <!-- 遮罩层 -->
        <div v-if="tipState" class="marker"></div>
        <div v-if="successful" class="marker"></div>
      </div>
      <!-- 列提示 -->
      <div class="col-hints">
        <div
          class="col-hints-box"
          v-for="(colHint, index) in colHintsArray"
          :key="'col-hint-' + index + Math.random() * 1000000"
          @click="tipClick('col', index)"
        >
          <p
            v-for="hint in colHint"
            :key="'col-hint_' + index + Math.random() * 1000000"
          >
            {{ hint }}
          </p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      clickState: true, // 点击状态 true为填充 false为打叉
      tipNumber: 1, // 提示次数最多次数根据各自数量定义
      tipState: false, // 是否在提示状态
      cellNumber: 3, // 格子数
      cellOptions: [
        { label: "3 x 3", value: 3, tip: 1 },
        { label: "5 x 5", value: 5, tip: 1 },
        { label: "8 x 8", value: 8, tip: 2 },
        { label: "10 x 10", value: 10, tip: 2 },
        { label: "12 x 12", value: 12, tip: 3 },
        { label: "15 x 15", value: 15, tip: 3 },
      ], // 格子数配置数组
      sukudoArray: [], // 原数组
      cellArray: [], // 用户填充的数组
      rowHintsArray: [], // 每行的提示数组
      colHintsArray: [], // 每列的提示数组
      successful: false, // 是否成功
    };
  },
  created() {
    this.generateSukodu();
  },
  methods: {
    // 生成数独
    generateSukodu() {
      this.successful = false;
      const fountItem = this.cellOptions.find(
        (item) => item.value == this.cellNumber
      );
      this.tipNumber = fountItem.tip;
      // 先生成空网格数组做初始对象，给用户填写
      this.cellArray = Array(this.cellNumber)
        .fill()
        .map(() => Array(this.cellNumber).fill(0));
      // 创建初始队列
      const result = [];
      for (let i = 0; i < this.cellNumber; i++) {
        const row = [];
        for (let j = 0; j < this.cellNumber; j++) {
          row.push(Math.random() < 0.5 ? 0 : 1);
        }
        result.push(row);
      }
      this.sukudoArray = result;
      this.generateHints();
    },
    // 生成提示
    generateHints() {
      const hintsForLine = (line) => {
        let hints = [];
        let count = 0;
        for (let i = 0; i < line.length; i++) {
          if (line[i] === 1) {
            count++;
          } else if (count > 0) {
            hints.push(count);
            count = 0;
          }
        }
        if (count > 0) {
          hints.push(count); // 如果最后有连续的 1
        }
        // 如果没有任何连续的 1，则返回 [0]
        if (hints.length === 0) {
          hints.push(0);
        }
        return hints;
      };
      // 生成行提示
      this.rowHintsArray = this.sukudoArray.map((row) => hintsForLine(row));
      // 生成列提示
      const colHints = [];
      for (let colIndex = 0; colIndex < this.cellNumber; colIndex++) {
        const column = this.sukudoArray.map((row) => row[colIndex]); // 提取列数据
        colHints.push(hintsForLine(column)); // 使用公共函数处理列
      }
      this.colHintsArray = colHints;
    },
    // 点击格子
    cellClick(rowIndex, colIndex) {
      const value = this.cellArray[rowIndex][colIndex];
      // 填充逻辑
      const handleFill = () => {
        if (value == 2) {
          this.$message.warning("该格子已被标记");
        } else {
          this.$set(this.cellArray[rowIndex], colIndex, value == 1 ? 0 : 1);
        }
      };
      // 标记逻辑
      const handleMark = () => {
        if (value == 1) {
          this.$message.warning("该格子已被填充");
        } else {
          this.$set(this.cellArray[rowIndex], colIndex, value == 2 ? 0 : 2);
        }
      };
      // 根据状态判断
      this.clickState ? handleFill() : handleMark();
      // 查看是否完成
      this.checkState();
    },
    // 提示
    tipClick(type, index) {
      if (!this.tipState) return false;
      if (this.tipNumber <= 0) {
        return this.$message.warning("已经超出提示次数了");
      }
      // 行提示
      if (type == "row") {
        this.cellArray[index] = this.sukudoArray[index].map((num) =>
          num == 1 ? 1 : 2
        );
      } else {
        this.sukudoArray.forEach((item, sukudoIndex) => {
          this.cellArray[sukudoIndex][index] = item[index] == 1 ? 1 : 2;
        });
      }
      this.tipNumber--;
      if (this.tipNumber == 0) {
        this.tipState = false;
      }
    },
    // 完成方法
    checkState() {
      let count = 0;
      for (let i = 0; i < this.cellNumber; i++) {
        let arr = this.cellArray[i].map((item) => {
          return item == 2 ? 0 : item;
        });
        let userCell = arr.join("");
        let defaultCell = this.sukudoArray[i].join("");

        if (userCell != defaultCell) {
          count = -1;
          break;
        } else {
          count++;
        }
      }
      if (count == this.cellNumber) {
        this.$message.success("恭喜完成此次数独");
        this.successful = true;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
div {
  box-sizing: border-box;
}

#sukodu {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 0 10vw;

  .select-box {
    width: 100%;
    margin-bottom: 24px;
    text-align: left;

    .el-select {
      width: 100px;
      margin-right: 10px;
    }
  }

  .position-box {
    width: 80vw;
    height: 65vw;
    max-width: 800px;
    max-height: 650px;
    position: relative;

    .row-hints {
      position: absolute;
      height: 100%;
      width: 15vw;
      max-width: 150px;
      max-height: 650px;
      top: 0;
      right: 0;
      display: flex;
      justify-content: flex-start;
      align-items: flex-start;
      flex-direction: column;

      .row-hints-box {
        width: auto;
        height: calc(100% / var(--cell-number));
        display: flex;
        justify-content: flex-start;
        align-items: center;
        cursor: pointer;
        user-select: none;

        p {
          font-size: 14px;
          margin-left: 10px;
        }
      }
    }

    .sukodu-box {
      width: 65vw;
      height: 65vw;
      max-height: 650px;
      max-width: 650px;
      border: 1px solid #999;

      .row-box {
        height: calc(100% / var(--cell-number));
        border-bottom: 1px solid #999;
        box-sizing: border-box;
        display: flex;
        justify-content: center;
        align-items: center;

        &:last-child {
          border: none;
        }

        .col-box {
          width: calc(100% / var(--cell-number));
          height: 100%;
          border-right: 1px solid #999;
          box-sizing: border-box;
          cursor: pointer;

          &:last-child {
            border: none;
          }
        }

        // 填充
        .col-stuff {
          background-color: #0061f3;
        }
        // 标记
        .col-mark {
          background-color: #ff3737;
        }
      }
    }
  }

  .col-hints {
    width: 65vw;
    max-width: 650px;
    display: flex;
    justify-content: center;
    align-items: flex-start;

    .col-hints-box {
      width: calc(100% / var(--cell-number));
      cursor: pointer;
      user-select: none;

      p {
        font-size: 14px;
        margin-top: 10px;
      }
    }
  }

  // 遮罩层
  .marker {
    position: absolute;
    bottom: 0;
    left: 0;
    width: 65vw;
    height: 65vw;
    max-width: 650px;
    max-height: 650px;
    background-color: rgba($color: #000000, $alpha: 0.2);
  }
}

// 媒体查询
@media screen and (max-width: 425px) {
  p {
    font-size: 12px !important;
  }

  .col-hints-box {
    p {
      margin-top: 4px !important;
    }
  }

  .row-hints-box {
    p {
      margin-left: 4px !important;
    }
  }
}
</style>
